package com.winter.portal.server.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.winter.portal.api.dto.ResourceDTO;
import com.winter.portal.api.vo.LeftMenuVO;
import com.winter.portal.api.vo.MenuInfoVO;
import com.winter.portal.api.vo.ResourceVO;
import com.winter.portal.server.auth.cache.AccessService;
import com.winter.portal.server.auth.cache.AuthorizationCacheService;
import com.winter.portal.server.auth.constant.AuthConstant;
import com.winter.portal.server.auth.service.SessionService;
import com.winter.portal.server.entity.ResourceEntity;
import com.winter.portal.server.entity.RoleResourceEntity;
import com.winter.portal.server.enums.ErrorCodeEnum;
import com.winter.portal.server.mapper.ResourceMapper;
import com.winter.portal.server.service.ResourceService;
import org.jzyan.framework.core.exception.BusinessException;
import org.jzyan.framework.core.utils.ConvertUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.*;

/**
 * <p>
 * 系统资源表 服务实现类
 * </p>
 *
 * @author jzyan
 * @since 2023-02-07
 */
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, ResourceEntity> implements ResourceService, AccessService {
    @Autowired
    private SessionService sessionService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AuthorizationCacheService cacheService;

    /**
     * 资源列表
     *
     * @return
     */
    @Override
    public List<ResourceVO> table() {
        List<ResourceEntity> list = list();
        return ConvertUtil.convert(list, ResourceVO.class);
    }

    /**
     * 左侧菜单
     *
     * @return
     */
    @Override
    public LeftMenuVO menuTree() {
        LeftMenuVO leftMenuVO = new LeftMenuVO();
        LeftMenuVO.HomeInfo homeInfo = new LeftMenuVO.HomeInfo();
        homeInfo.setTitle("首页");
        homeInfo.setHref("route/welcome");
        leftMenuVO.setHomeInfo(homeInfo);
        LeftMenuVO.HomeInfo logoInfo = new LeftMenuVO.HomeInfo();
        logoInfo.setTitle("LAYUI MINI");
        logoInfo.setImage("images/logo.png");
        leftMenuVO.setLogoInfo(logoInfo);
        Map<String, Object> map = new HashMap<>(2);
        map.put("isRoot", sessionService.getUser().getRoot());
        if (!sessionService.isRoot() && CollectionUtils.isEmpty(sessionService.getRoleIds())) {
            map.put("roleIds", -1);
        } else {
            map.put("roleIds", sessionService.getRoleIds());
        }
        List<ResourceEntity> list = baseMapper.leftMenu(map);
        List<MenuInfoVO> menuInfoList = new ArrayList<>();
        for (ResourceEntity result : list) {
            if (result.getParentId() == 0) {
                //调用方法给子类添加数据
                MenuInfoVO menuInfo = new MenuInfoVO();
                menuInfo.setId(result.getId());
                menuInfo.setTitle(result.getResourceName());
                menuInfo.setHref(result.getUrl());
                menuInfo.setIcon(result.getIcon());
                menuInfo.setTarget("_self");
                menuInfoList.add(getMenuTree(menuInfo, list));
            }
        }
        MenuInfoVO baseMenuInfo = new MenuInfoVO();
        baseMenuInfo.setTitle("菜单");
        baseMenuInfo.setHref("");
        baseMenuInfo.setIcon("fa fa-address-book");
        baseMenuInfo.setTarget("_self");
        baseMenuInfo.setChild(menuInfoList);
        List<MenuInfoVO> baseMenuInfoList = new ArrayList<>();
        baseMenuInfoList.add(baseMenuInfo);
        leftMenuVO.setMenuInfo(baseMenuInfoList);
        return leftMenuVO;
    }

    /**
     * 添加资源
     *
     * @param resource
     */
    @Override
    public void add(ResourceDTO resource) {
        ResourceEntity resourceEntity;
        if (!ObjectUtils.isEmpty(resource.getPermission())) {
            resourceEntity = baseMapper.selectOne(Wrappers.<ResourceEntity>lambdaQuery()
                    .eq(ResourceEntity::getPermission, resource.getPermission()));
            if (!ObjectUtils.isEmpty(resourceEntity)) {
                throw new BusinessException(ErrorCodeEnum.CODE_1502016);
            }
        }
        if (!ObjectUtils.isEmpty(resource.getUrl())) {
            resourceEntity = baseMapper.selectOne(Wrappers.<ResourceEntity>lambdaQuery()
                    .eq(ResourceEntity::getUrl, resource.getUrl()));
            if (!ObjectUtils.isEmpty(resourceEntity)) {
                throw new BusinessException(ErrorCodeEnum.CODE_1502017);
            }
        }
        resourceEntity = ConvertUtil.convert(resource, ResourceEntity.class);
        baseMapper.insert(resourceEntity);
    }

    /**
     * 删除资源
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        Long count = baseMapper.selectCount(Wrappers.<ResourceEntity>lambdaQuery()
                .eq(ResourceEntity::getParentId, id));
        if (count > 0) {
            throw new BusinessException(ErrorCodeEnum.CODE_1502015);
        }
        baseMapper.deleteById(id);
        baseMapper.deleteRoleResurceByResId(id);
        // 清除访问权限缓存
        cacheService.removeAccess();
    }

    /**
     * 角色资源
     *
     * @param roleId
     * @return
     */
    @Override
    public List<RoleResourceEntity> getRoleResource(Serializable roleId) {
        return baseMapper.getRoleResource(roleId);
    }

    /**
     * 更新
     *
     * @param resource
     */
    @Override
    public void update(ResourceDTO resource) {
        ResourceEntity resourceEntity = ConvertUtil.convert(resource, ResourceEntity.class);
        updateById(resourceEntity);
        // 清除访问权限缓存
        cacheService.removeAccess();
    }

    /**
     * 递归获取菜单Tree
     *
     * @param result
     * @param list
     * @return
     */
    private MenuInfoVO getMenuTree(MenuInfoVO result, List<ResourceEntity> list) {
        for (ResourceEntity resourceEntity : list) {
            //如果父类主键等于传过来实体类的ID
            if (resourceEntity.getParentId().equals(result.getId())) {
                MenuInfoVO menuInfo = new MenuInfoVO();
                menuInfo.setId(resourceEntity.getId());
                menuInfo.setTitle(resourceEntity.getResourceName());
                menuInfo.setHref(resourceEntity.getUrl());
                menuInfo.setIcon(resourceEntity.getIcon());
                menuInfo.setTarget("_self");
                if (result.getChild() == null) {
                    result.setChild(new ArrayList<>());
                }
                // 递归调用
                result.getChild().add(getMenuTree(menuInfo, list));
            }
        }
        return result;
    }

    /**
     * 根据uri 获取用户角色id集合
     *
     * @param uri
     * @return
     */
    @Override
    public Set<Long> getRolesByUri(String uri) {
        Set<Long> roleIds;
        Object obj = redisTemplate.opsForHash().get(AuthConstant.AUTH_ACCESS_PREFIX, uri);
        if (obj == null) {
            roleIds = baseMapper.getRoleIdsByUri(uri);
            redisTemplate.opsForHash().put(AuthConstant.AUTH_ACCESS_PREFIX, uri, roleIds);
        } else {
            roleIds = new HashSet<>();
            List<Integer> list = (List<Integer>) obj;
            list.forEach(e -> {
                roleIds.add(Long.valueOf(e.toString()));
            });
        }
        return roleIds;
    }

}
